{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit Scrolling;

interface

uses AHMTypes;

const
  // Text scroll speeds measured in fraction of screen per second
  TEXT_FORWARD_SPEED = 0.03;
  TEXT_REVERSE_SPEED = 0.06;

  // Pauses before scrolling text in each direction measured in ms.
  TEXT_FORWARD_PAUSE = 2000;
  TEXT_REVERSE_PAUSE = 1000;

type
  TAHMScrollState = (ssIdle, ssPauseFront, ssForward, ssPauseEnd, ssBackward);

  TAHMAbstractScroller = class
  protected
    FMaxExtent: Boolean;
    FEnabled: Boolean;
    FVertical: Boolean;
    FPosition: Single;
    FDisplayTime: Single;
    procedure ResetScroll; virtual;
    procedure UpdateScroll; virtual;
  public
    property Scrolling: Boolean read FEnabled write FEnabled;
    property Vertical: Boolean read FVertical write FVertical;
    property Position: Single read FPosition;
    procedure Assign(Source: TAHMAbstractScroller); virtual;
    procedure ScrollingRequired; virtual;
  end;

  TAHMTextScroller = class(TAHMAbstractScroller)
  private
    FScrollText: String;
    FTimestamp: TAHMTimestamp;
    FState: TAHMScrollState;
    FFwdPause: Integer;
    FBkwdPause: Integer;
    FFwdSpeed: Single;
    FBkwdSpeed: Single;
  protected
    procedure SetScrollText(Text: String);
    procedure ResetScroll; override;
    procedure UpdateScroll; override;
  public
    constructor Create;
    property ScrollText: String read FScrollText write SetScrollText;
    property ForwardSpeed: Single read FFwdSpeed write FFwdSpeed;
    property BackwardSpeed: Single read FBkwdSpeed write FBkwdSpeed;
    property ForwardPause: Integer read FFwdPause write FFwdPause;
    property BackwardPause: Integer read FBkwdPause write FBkwdPause;
    procedure Assign(Source: TAHMAbstractScroller); override;
  end;

implementation

uses Timing;

// TAHMAbstractScroller

procedure TAHMAbstractScroller.ResetScroll;
begin
  FPosition := 0.0;
  FDisplayTime := 0.0;
  FMaxExtent := True;
end;

procedure TAHMAbstractScroller.UpdateScroll;
begin
  // Descendants will override this as required
end;

procedure TAHMAbstractScroller.Assign(Source: TAHMAbstractScroller);
begin
  if Source is TAHMAbstractScroller then
    FVertical := TAHMAbstractScroller(Source).Vertical;
end;

procedure TAHMAbstractScroller.ScrollingRequired;
begin
  // We need to scroll this scroller, so enable scrolling. Also we know that
  // we have not reached the maximum scroll extent, so clear our flag
  FEnabled := True;
  FMaxExtent := False;
end;

// TAHMTextScroller

constructor TAHMTextScroller.Create;
begin
  inherited;

  // Set default scroll speeds & pauses
  FFwdSpeed := TEXT_FORWARD_SPEED;
  FBkwdSpeed := TEXT_REVERSE_SPEED;
  FFwdPause := TEXT_FORWARD_PAUSE;
  FBkwdPause := TEXT_REVERSE_PAUSE;

  // Reset scroll
  ResetScroll;
end;

procedure TAHMTextScroller.SetScrollText(Text: String);
begin
  // if this is a new string then reset scrolling
 if Text <> FScrollText then
  begin
    FScrollText := Text;
    ResetScroll;
  end
  else if FEnabled then
    UpdateScroll;
end;

procedure TAHMTextScroller.ResetScroll;
begin
  inherited;

  FState := ssIdle;
end;

procedure TAHMTextScroller.UpdateScroll;
var
  FrameTime: Integer;
begin
  // Get elapsed frame time to regulate scrolling animations
  FrameTime := TimerInstance.CurrentFrameTime;
  if FrameTime = 0 then Exit;

  // Action depends on current state
  case FState of
    ssIdle:
    begin
      // Reset timer for pause at front
      FTimestamp := TimerInstance.CurrentTimeStamp;
      FState := ssPauseFront;
    end;
    ssPauseFront:
    begin
      // If front pause has elapsed, then scroll forwards
      if TimerInstance.HasDurationElapsed(FTimestamp, FFwdPause) then
      begin
        FState := ssForward;
        FDisplayTime := 0.0;
      end;
    end;
    ssForward:
    begin
      // Scroll forwards until we exceed maximum extent
      FPosition := FPosition + (FFwdSpeed * FrameTime / 1000);
      if FMaxExtent then
      begin
        // Reset timer for pause at front
        FTimestamp := TimerInstance.CurrentTimeStamp;
        FState := ssPauseEnd;
      end;
    end;
    ssPauseEnd:
    begin
      // If end pause has elapsed, then scroll backwards
      if TimerInstance.HasDurationElapsed(FTimestamp, FBkwdPause) then
      begin
        FState := ssBackward;
        FDisplayTime := 0.0;
      end;
    end;
    ssBackward:
    begin
      // Scroll backwards until we exceed start point
      FPosition := FPosition - (FBkwdSpeed * FrameTime / 1000);
      if FPosition < 0 then
        FState := ssIdle;
    end;
  end;

  // Reset our maximum extent flag
  FMaxExtent := True;
end;

procedure TAHMTextScroller.Assign(Source: TAHMAbstractScroller);
begin
  inherited;

  if Source is TAHMTextScroller then
    with Source as TAHMTextScroller do
    begin
      Self.ForwardSpeed := ForwardSpeed;
      Self.BackwardSpeed := BackwardSpeed;
      Self.ForwardPause := ForwardPause;
      Self.BackwardPause := BackwardPause;
    end;

  // Stop any current scrolling
  ResetScroll;
end;


end.
